mod app;
mod parser;
pub mod tools;

use std::collections::HashMap;

pub use app::*;
pub use parser::Parser;

#[macro_use]
extern crate serde;

#[macro_use]
extern crate nickel;
use nickel::{status::StatusCode, HttpRouter,  QueryString};

use file_sql::{AppData, Editor, FQLType, Reader, ForceUnwrap};
use tools::provide_welcome_html;

/// json 格式化输出
#[derive(Debug, Serialize)]
pub struct JsonRes<T> {
    msg: String,
    data: T,
}

impl<T> JsonRes<T> {
    pub fn new(data: T) -> Self {
        Self {
            msg: "success".to_string(),
            data,
        }
    }

    pub fn msg<U: std::fmt::Display>(mut self, msg: U) -> Self {
        self.msg = format!("{}", msg);
        self
    }
}

/// 实现 curd
pub fn curd_implement(app: &crate::App, server: &mut nickel::Nickel) { 

    let html = provide_welcome_html(&app);
    server.get("/", middleware!(format!("{}", html)));

    for service in &app.services {
        let root_file = format!("{}/{}", app.dir, &service.file); 

         
        let file = root_file.clone(); 
        let url = service.url.clone();
        server.get(
            url.clone(),
            middleware! { |request|

                let mut query = HashMap::new();
                let mut msg = String::from("success");
                let mut res = file_sql::App::from_file(&file).force_unwrap();
 
                let keys = res.keys.clone();

                for key in keys {
                    if let Some(param) = request.query().get(&key) {
                        query.insert(key.to_string(), param.to_string());
                        res = file_sql::App::from(res.find_all(key, FQLType::from(param)));
                    }
                }

                if res.data.len() == 0 {
                    msg = String::from("no result");
                }

                if let Some(param) = request.query().get("$index") {
                    query.insert("$index".to_string(), param.to_string());
                    res = file_sql::App::from(res.find_all("$index", FQLType::from(param)));
                    if res.data.len() == 0  {
                        msg = String::from("invalid index");
                    }
                }



                println!("GET[\"{}\"]: {:?}",  url, query);

                let json = JsonRes::new(res.serialize()).msg(msg);
                serde_json::to_value(json).map_err(|e| (StatusCode::InternalServerError, e))
            },
        );
 
        let file = root_file.clone(); 
        let url = service.url.clone();
        server.post(
            url.clone(),
            middleware! { |request|
  
                let mut msg = String::from("success");
                let mut query: HashMap<String, FQLType> = HashMap::new();

                let mut res = file_sql::App::from_file(&file).force_unwrap();
                let keys = res.keys.clone();

                for key in &keys { 
                    query.insert(key.to_string(), request.query().get(key).map_or(FQLType::Null, |v| FQLType::from(v)));
                }

                
                let new_data = AppData::from(query);
                let json = JsonRes::new(new_data.serialize());
                println!("POST[\"{}\"]: {:?}", url, new_data.serialize());

                if let Some(param) = request.query().get("$index") {
                    if let Some(index) = res.find_index("$index", FQLType::from(param)) {
                        res.replace(index, new_data);
                        msg = format!("replace data at index {}", index);
                    }
                } else {
                    res.add(new_data);
                    msg = format!("add data at index {}", res.data.len());
                }

                res.save_at(&file);
                serde_json::to_value(json.msg(msg)).map_err(|e| (StatusCode::InternalServerError, e))

            },
        );


        let file = root_file.clone(); 
        let url = service.url.clone();
        server.delete(
            url.clone(),
            middleware! { |request|
  
                let mut msg = String::new();
                let mut query: HashMap<String, String> = HashMap::new();
                let mut res = file_sql::App::from_file(&file).force_unwrap();
 
                if let Some(param) = request.query().get("$index") {
                    query.insert("$index".to_string(), param.to_string());
                    if let Some(index) = res.find_index("$index", FQLType::from(param)) {
                        res.remove(index);
                        msg = format!("remove data at index {}", index);
                    } else {
                        msg = String::from("invalid index");
                    }
                } else { 
                    msg = String::from("missing index");
                }

                res.save_at(&file);
                println!("DELETE[\"{}\"]: {:?}", url, query);
                serde_json::to_value(JsonRes::new(query).msg(msg)).map_err(|e| (StatusCode::InternalServerError, e))

            },
        );
    }
}
